'''
    Rockaby: a text annotation system
    Copyright 2010 Martin Paul Eve

    This file is part of Rockaby.

    Rockaby is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    Rockaby is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with Rockaby.  If not, see <http://www.gnu.org/licenses/>.

'''

import re
import rockaby.parts

class ReferenceEngine(object):

    def __init__(self, input):
        self.referencetext = input
        self.references = []
        self.referencetable = ''
        self.internalReferences()
        self.externalReferences()
        
    def internalReferences(self):
        '''
        A function that looks for references within the text itself and links to their episode
        '''
        internalRefRegex = '\[episode part\="([^"]+)?" episode\="([^"]+)?" page\="([^"]+)?"\]'
        regex = re.compile(internalRefRegex)
        
        matches = regex.finditer(self.referencetext)

        GravitysRainbow = BookReference()
        GravitysRainbow.AuthorFirstName = "Thomas"
        GravitysRainbow.AuthorLastName = "Pynchon"
        GravitysRainbow.Location = "London"
        GravitysRainbow.Publisher = "Vintage"
        GravitysRainbow.Title = "Gravity's Rainbow"
        GravitysRainbow.Year = '2000'
        
        for match in matches:
            partNumber = match.group(1)
            episodeNumber = match.group(2)
            pageNumber = match.group(3)
            sanitizedPartName = rockaby.parts.Parts.SanitizedPartNames[int(partNumber)]
            formattedPartName = rockaby.parts.Parts.FormattedPartNames[int(partNumber)]

            GravitysRainbow.Page = pageNumber

            inlineEpisodeReference = '<span class="blacklink"><a title="' + formattedPartName + ': Episode ' + episodeNumber + ', page ' + pageNumber + '" href="/' + sanitizedPartName + '/synopsis/episode_' + episodeNumber + '">' + formattedPartName + ': Episode ' + episodeNumber + '</a></span>'
                
            self.referencetext = self.referencetext.replace(match.group(0), inlineEpisodeReference + GravitysRainbow.ReferenceText())

    def externalReferences(self):
        '''
        A function that parses references
        '''
        externalRefRegex = '\[ref type\="([^"]+)?"( authorfirst\="([^"]+)?" authorlast\="([^"]+)?" title\="([^"]+)?" year\="([^"]+)?" publisher\="([^"]+)?" location\="([^"]+)?" page\="([^"]+)?")?( authorfirst\="([^"]+)?" authorlast\="([^"]+)?" url\="([^"]+)?" accessdate\="([^"]+)?")?\]'
        regex = re.compile(externalRefRegex)
        
        matches = regex.finditer(self.referencetext)

        referenceTable = '<div><ol class="references">'

        counter = 0;
        
        for match in matches:
            thematch = match.group(0)
            type = match.group(1)
                
            refr = BookReference()

            if type == 'book':
                br = BookReference()
                br.Match = thematch;
                br.AuthorFirstName = match.group(3)
                br.AuthorLastName = match.group(4)
                br.Title = match.group(5)
                br.Year = match.group(6)
                br.Publisher = match.group(7)
                br.Location = match.group(8)
                br.Page = match.group(9)
                refr = br
            elif type == 'web':
                wr = WebReference()
                wr.Match = thematch
                wr.AuthorFirstName = match.group(11)
                wr.AuthorLastName = match.group(12)
                wr.Url = match.group(13)
                wr.AccessDate = match.group(14)
                refr = wr

            # establish if this reference already exists 
            dupe = False
            
            for r in self.references:
                if r.Match == thematch:
                    dupe = True
                    break

            if not dupe:
                self.references.append(refr)


        alreadyUsedReferences = {}
            
        for r in self.references:
            # ascertain if this reference has already
            # been used by indexing on reference without
            # page number
            useFull = not alreadyUsedReferences.has_key(r.ReferenceTextNoPageNumber())
            
            # add the reference to the already used list
            if useFull:
                alreadyUsedReferences[r.ReferenceTextNoPageNumber()] = r
                
            # build the inline links
            currentPosition = 0
            linkCount = 0
            
            for numberOfLinks in range(0, 500):
                currentPosition = self.referencetext.find(r.Match, currentPosition)
                
                if not currentPosition == -1:
                    rebuilt = self.referencetext[0:currentPosition] + '<span class="reference"><sup id="ref' + str((counter + 1)) + 'indoc' + str((numberOfLinks + 1)) + '"><a href="#ref' + str((counter + 1)) + '" title="' + r.ReferenceTextFullNoFormatting() + '">' + str((counter + 1)) + '</a></sup></span>'  + self.referencetext[(currentPosition + len(r.Match)):len(self.referencetext)]
                    self.referencetext = rebuilt
                else:
                    linkCount = numberOfLinks
                    break


            if linkCount == 1:
                # single link to this reference
                if useFull:
                    referenceTable = referenceTable + '<li id="ref' + str((counter + 1)) + '"><b><a href="#ref' + str((counter + 1)) + 'indoc1" title="Go to referring text">^</a></b>' + r.ReferenceTextFull() + '</li>'
                else:
                    referenceTable = referenceTable + '<li id="ref' + str((counter + 1)) + '"><b><a href="#ref' + str((counter + 1)) + 'indoc1" title="Go to referring text">^</a></b>' + r.ReferenceTextShort() + '</li>'
            else:
                # multiple links to this reference
                referenceTable = referenceTable + '<li id="ref' + str((counter + 1)) + '">^ '
                
                for linkCounter in range(1, linkCount + 1):
                    referenceTable = referenceTable + '<b>[<a href="#ref' + str((counter + 1)) + 'indoc' + str(linkCounter) + '" title="Go to referring text">' + str(linkCounter) + '</a>]</b>'
                
                if useFull:
                    referenceTable = referenceTable + ' ' + r.ReferenceTextFull() + '</li>'
                else:
                    referenceTable = referenceTable + ' ' + r.ReferenceTextShort() + '</li>'

                    
            counter = counter + 1
                

        referenceTable = referenceTable + '</ol></div>'
        self.referencetable = referenceTable
                         
                         
class WebReference(object):
    
    def __init__(self):
        self.AuthorFirstName = ''
        self.AuthorLastName = ''
        self.Url = ''
        self.AccessDate = ''
        self.Match = ''
        
    def ReferenceText(self):
        return '[ref type="web" authorfirst="' + self.AuthorFirstName + '" authorlast="' + self.AuthorLastName + '" url="' + self.Url + '" accessdate="' + self.AccessDate +'"]'
    
    def ReferenceTextNoPageNumber(self):
        return self.AuthorLastName + ', ' + self.AuthorFirstName + ', <i><a href="' + self.Url + '" title="External Reference">' + self.Url + '</a></i> (accessed: ' + self.AccessDate +')'
        

    def ReferenceTextFull(self):
        return self.AuthorLastName + ', ' + self.AuthorFirstName + ', <i><a href="' + self.Url + '" title="External Reference">' + self.Url + '</a></i> (accessed: ' + self.AccessDate +')'


    def ReferenceTextFullNoFormatting(self):
        return str(self.AuthorLastName) + ', ' + str(self.AuthorFirstName) + ', ' + str(self.Url)  + ' (accessed: ' + str(self.AccessDate) + ')'

    def ReferenceTextShort(self):
        return str(self.AuthorLastName) + ', ' + str(self.AuthorFirstName) + ', <i><a href="' + str(self.Url) + '" title="External Reference">' + str(self.Url) + '</a></i> (accessed: ' + str(self.AccessDate) +')'

class BookReference(object):
    
    def __init__(self):
        self.AuthorFirstName = ''
        self.AuthorLastName = ''
        self.Location = ''
        self.Publisher = ''
        self.Title = ''
        self.Year = ''
        self.Page = ''
        self.Match = ''
        
    def ReferenceText(self):
        return '[ref type="book" authorfirst="' + self.AuthorFirstName + '" authorlast="' + self.AuthorLastName + '" title="' + self.Title + '" year="' + self.Year + '" publisher="' + self.Publisher + '" location="' + self.Location + '" page="' + self.Page + '"]'
    
    def ReferenceTextNoPageNumber(self):
        return self.AuthorLastName + ', ' + self.AuthorFirstName + ', <i>' + self.Title + '</i> (' + self.Location + ': ' + self.Publisher + ', ' + self.Year + ')'
        

    def ReferenceTextFull(self):
        return self.AuthorLastName + ', ' + self.AuthorFirstName + ', <i>' + self.Title + '</i> (' + self.Location + ': ' + self.Publisher + ', ' + self.Year + '), p. ' + self.Page + '.'


    def ReferenceTextFullNoFormatting(self):
        return self.AuthorLastName + ', ' + self.AuthorFirstName + ', ' + self.Title + ' (' + self.Location + ': ' + self.Publisher + ', ' + self.Year + ')'

    def ReferenceTextShort(self):
        return self.AuthorLastName + ', <i>' + self.Title + '</i>, p. ' + self.Page + '.'
        